
#ifndef MOREBATCH_HH
#define MOREBATCH_HH
#include <click/ipaddress.hh>
#include <click/vector.hh>
#include <click/packet.hh>
#include <click/etheraddress.hh>
#include "morepacket.hh"
#include "codedblock.hh"
#include "matrix.hh"
#include "matrixmgr.hh"

CLICK_DECLS

#define PRE_ENCODE 1

/**
 * Contains all code state.
 */
class MOREBatch {
    public:
        /**
         * Contains per-batch state that should remain fixed for lifetime.
         */
        struct Config {
            int k;
            int datasize;

            // routing
            uint32_t metric; // used primarily for credit distribution
            int rate; // rate to use for DATA packets (MadWifi 2x!), use -1 if pruned

            mutable uint _txtime; // cached

            Config(): k(0), datasize(0), metric(0), rate(-1), _txtime(0) {}
            uint txtime() const;
        };

        const Config _c;
    protected:
        const uint32_t _seqno;
        uint32_t _tx; // # of txes in this batch - forms a unique packet identifier with src mac and batch seqno

        // code state
        FullGEMatrix _D; // at sink
        MatrixMgr _M; // at forwarder
    public:
        MOREBatch(uint32_t seqno, const Config &c) :
                _c(c), _seqno(seqno), _tx(0),
                _D(c.k, c.datasize), _M(c.k, c.datasize),
                _credit(0.0)
        {
            // prepare the packet straight away
            prepare();
        }
        ~MOREBatch() { _D.clear(); }

        /** Accessors **/
        uint seqno() const { return _seqno; }
        const Config& c() const { return _c; }

        const FullGEMatrix &D() const { return _D; }
        const MatrixMgr &M() const { return _M; }
        const Matrix &I() const { return _M.I(); }

        /** batch output **/
        WritablePacket* take();

        // XXX this is NOT INDEMPOTENT
        void prepare(WritablePacket *p = 0) {
            // p points at more_pkt FIXME so that it's smarter
            if(p) {
                // make it point at more_block
                p->pull(sizeof(more_pkt) + sizeof(more_data));
            }
            _M.prepare(p);
        }

    // HACK! either _M or _D is in use
        int rank() const { return _M.rank() + _D.rank(); }
        bool full() const { return rank() == _c.k; }
        bool queued() const {
            return (_credit >= 1.0);
        }

    // these methods expect that p starts with the more_block
        // NOTE: decode and forward take the packet (don't use it again!)
        bool decode(Packet *p);
        bool forward(Packet *p);

        float _credit;      // credit remaining

        void source(WritablePacket *p);
};

#include <click/vector.cc>

CLICK_ENDDECLS
#endif // MOREBATCH_HH
